/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import fs from 'fs';
import Handlebars from 'handlebars';
import { FileUtil } from '@ohos/hvigor';
import { HMRouterPluginConfig } from './HMRouterPluginConfig';
import {
  AnalyzerResultLike,
  HMAnimatorResult,
  HMInterceptorResult,
  HMLifecycleResult,
  HMServiceResult,
  HMRouterResult,
  RouterInfo,
  TemplateModel,
} from './common/PluginModel';
import { Analyzer } from './HMRouterAnalyzer';
import { Logger, PluginError } from './common/Logger';
import { HMRouterPluginConstant } from './common/Constant';

// 定义HMRouterHvigorPlugin类
export class HMRouterHvigorPlugin {
  config: HMRouterPluginConfig;
  routerMap: RouterInfo[] = [];
  private scanFiles: string[] = [];
  private HMRouterNum: number = 0;

  constructor(config: HMRouterPluginConfig) {
    this.config = config;
  }

  analyzeAnnotation() {
    this.config.scanDir.forEach((dir) => {
      const scanPath = this.config.getScanPath(dir);
      this.deepScan(scanPath, '');
    });
    Logger.info(`Scanned ${this.scanFiles.length} files`, this.scanFiles);
    this.scanFiles.forEach((filePath) => {
      if (filePath.endsWith(HMRouterPluginConstant.VIEW_NAME_SUFFIX)) {
        // 创建Analyzer对象
        const analyzer = new Analyzer(filePath, this.config);
        // 开始分析
        analyzer.start();
        // 遍历分析结果
        for (let analyzeResult of analyzer.analyzeResultSet) {
          analyzeResult.module = this.config.moduleName;
          let pageSourceFile = this.config.getRelativeSourcePath(filePath);
          this.pushRouterInfo(
            analyzeResult,
            pageSourceFile.replaceAll(HMRouterPluginConstant.FILE_SEPARATOR, HMRouterPluginConstant.DELIMITER)
          );
        }
        this.HMRouterNum = 0;
      }
    });
  }

  // 推送路由信息
  private pushRouterInfo(analyzeResult: AnalyzerResultLike, pageSourceFile: string) {
    // 判断注解类型
    switch (analyzeResult.annotation) {
      case HMRouterPluginConstant.ROUTER_ANNOTATION:
        this.HMRouterNum++;
        // 判断是否存在多个HMRouter注解
        if (this.HMRouterNum > 1) {
          Logger.error(PluginError.ERR_REPEAT_ANNOTATION, pageSourceFile);
          throw new Error(`文件${pageSourceFile}中存在多个HMRouter注解`);
        }
        let [generatorFilePath, componentName] = this.generateBuilder(analyzeResult, pageSourceFile);
        // window环境下需要替换路径中的反斜杠
        generatorFilePath = generatorFilePath.replaceAll(
          HMRouterPluginConstant.FILE_SEPARATOR,
          HMRouterPluginConstant.DELIMITER
        );
        this.routerMap.push(
          new RouterInfo(
            (analyzeResult as HMRouterResult).pageUrl as string,
            generatorFilePath,
            `${componentName}Builder`,
            analyzeResult
          )
        );
        break;
      case HMRouterPluginConstant.ANIMATOR_ANNOTATION:
        let animatorName = HMRouterPluginConstant.ANIMATOR_PREFIX + (analyzeResult as HMAnimatorResult).animatorName;
        this.routerMap.push(new RouterInfo(animatorName, pageSourceFile, '', analyzeResult));
        break;
      case HMRouterPluginConstant.INTERCEPTOR_ANNOTATION:
        let interceptorName =
          HMRouterPluginConstant.INTERCEPTOR_PREFIX + (analyzeResult as HMInterceptorResult).interceptorName;
        this.routerMap.push(new RouterInfo(interceptorName, pageSourceFile, '', analyzeResult));
        break;
      case HMRouterPluginConstant.LIFECYCLE_ANNOTATION:
        let lifecycleName =
          HMRouterPluginConstant.LIFECYCLE_PREFIX + (analyzeResult as HMLifecycleResult).lifecycleName;
        this.routerMap.push(new RouterInfo(lifecycleName, pageSourceFile, '', analyzeResult));
        break;
      case HMRouterPluginConstant.SERVICE_ANNOTATION:
        let serviceName = HMRouterPluginConstant.SERVICE_PREFIX + (analyzeResult as HMServiceResult).serviceName;
        this.routerMap.push(new RouterInfo(serviceName, pageSourceFile, '', analyzeResult));
        break;
    }
  }

  // 生成Builder
  private generateBuilder(analyzeResult: HMRouterResult, pageSourceFile: string) {
    // 获取导入路径
    let importPath = this.config
      .getRelativeBuilderPath(pageSourceFile)
      .replaceAll(HMRouterPluginConstant.FILE_SEPARATOR, HMRouterPluginConstant.DELIMITER)
      .replaceAll(HMRouterPluginConstant.VIEW_NAME_SUFFIX, '');
    // 生成视图名称
    let generatorViewName =
      HMRouterPluginConstant.VIEW_NAME_PREFIX + analyzeResult.name + this.stringToHashCode(analyzeResult.pageUrl!);
    // 创建模板模型
    const templateModel: TemplateModel = new TemplateModel(
      analyzeResult.pageUrl,
      importPath,
      analyzeResult.name!,
      !!analyzeResult.dialog,
      generatorViewName
    );
    // 获取模板文件路径
    const templateFilePath = this.config.getTplFilePath();
    // 读取模板文件
    const tpl = FileUtil.readFileSync(templateFilePath).toString();
    // 编译模板
    const template = Handlebars.compile(tpl);
    // 渲染模板
    const output = template(templateModel);
    // 获取生成文件路径
    const generatorFilePath = this.config.getGeneratedFilePath(templateModel.generatorViewName);
    FileUtil.ensureFileSync(generatorFilePath);
    FileUtil.writeFileSync(generatorFilePath, output);
    Logger.info(`Builder ${templateModel.generatorViewName}.ets has been generated in ${generatorFilePath}`);
    // 返回生成文件路径和组件名称
    return [this.config.getBuilderFilePath(templateModel.generatorViewName), templateModel.componentName];
  }

  // 生成路由表文件
  generateRouterMap() {
    let set = new Set<string>();
    this.routerMap.forEach((item) => {
      // 判断路由名称是否重复
      if (set.has(item.name)) {
        Logger.error(PluginError.ERR_DUPLICATE_NAME, item.name);
        throw new Error(`路由${item.name}重复`);
      } else {
        set.add(item.name);
      }
    });
    let routerMap = {
      routerMap: this.routerMap.map((item) => {
        // 删除注解
        if (item.customData && item.customData.annotation) {
          delete item.customData.annotation;
        }
        return item;
      }),
    };

    // 获取路由映射文件路径
    const routerMapJsonStr = JSON.stringify(routerMap, null, 2);
    const routerMapFilePath = this.config.getRouterMapDir();
    // 确保文件存在
    FileUtil.ensureFileSync(routerMapFilePath);
    FileUtil.writeFileSync(routerMapFilePath, routerMapJsonStr);
    Logger.info(`hm_router_map.json has been generated in ${routerMapFilePath}`);
  }

  // 深度扫描文件夹获取需要扫描的文件列表
  private deepScan(scanPath: string, filePath: string) {
    let resolvePath = FileUtil.pathResolve(scanPath, filePath);
    if (FileUtil.exist(resolvePath) && FileUtil.isDictionary(resolvePath)) {
      const files: string[] = fs.readdirSync(resolvePath);
      files.forEach((file) => {
        this.deepScan(resolvePath, file);
      });
    } else {
      this.scanFiles.push(resolvePath);
    }
  }

  // 字符串转哈希码
  private stringToHashCode(str: string) {
    let hash = 0;
    if (str.length === 0) {
      return hash;
    }
    for (let i = 0; i < str.length; i++) {
      const char = str.charCodeAt(i);
      hash = (hash << 5) - hash + char;
      hash |= 0; // 转换为32位整数
    }
    return hash;
  }
}
